
#include <stdint.h>
#include "contract.h"
#include "clock_countor.h"
#include "ClockAlarmer.h"
#include "base.h"

#include "gd32w51x.h"

#define ETU_TIMER			TIMER5
#define ETU_TIMER_IRQn		TIMER5_IRQn
#define ETU_TIMER_CLK_ENABLE()  rcu_periph_clock_enable(RCU_TIMER5)
#define ETU_TIMER_CLK_FREQ()	(rcu_clock_freq_get(CK_APB1) * 2)

#define ETU_TIMER_CLEAR_COUNTOR()	timer_counter_value_config(ETU_TIMER, 0)
#define ETU_TIMER_SET_COUNTOR_PEAK(cnt) 	do{TIMER_CAR(ETU_TIMER) = (uint32_t)cnt;}while(0)
#define ETU_TIMER_GET_COUNTOR_PEAK() 		TIMER_CAR(ETU_TIMER)

volatile uint32_t etuTimerCountor;

void TIMER5_IRQHandler(void)
{
   timer_interrupt_flag_clear(ETU_TIMER, TIMER_INT_FLAG_UP);

   etuTimerCountor += 65536;
}


void ETUTimer_Init(uint32_t freq){

	etuTimerCountor = 0;

	timer_parameter_struct timer_initpara;
	ETU_TIMER_CLK_ENABLE();
	timer_deinit(ETU_TIMER);
	uint32_t clk = ETU_TIMER_CLK_FREQ();
	
	/* TIMER1 configuration */
	timer_initpara.prescaler         = clk / freq - 1;
	timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
	timer_initpara.counterdirection  = TIMER_COUNTER_UP;
	timer_initpara.period            = 0xFFFF;
	timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
	timer_init(ETU_TIMER, &timer_initpara);
	
	timer_interrupt_flag_clear(ETU_TIMER, TIMER_INT_FLAG_UP);
	timer_interrupt_enable(ETU_TIMER, TIMER_INT_UP);
	nvic_irq_enable(ETU_TIMER_IRQn, 0, 0);

	timer_enable(ETU_TIMER);
}

uint32_t ETUTimer_GetCountor(void){
	uint32_t count;
	uint32_t hwCount;
	do{
		count = etuTimerCountor;
		hwCount = timer_counter_read(ETU_TIMER);
	}while(count != etuTimerCountor);

	return count + hwCount;
}

void ETUTimer_Delay(uint32_t clk){
	uint32_t c1 = ETUTimer_GetCountor();
	uint32_t c2;
	do{
		c2 = ETUTimer_GetCountor();
	}while((c2 - c1) < clk);
}

uint32_t ETUTimer_ETU2Clock(uint32_t etu, uint8_t FiDi)
{
	uint32_t F, D;
	uint32_t clock;
	
	F = convert_fi_code_to_value(FiDi >> 4);
	D = convert_di_code_to_value(FiDi & 0x0F);

	if( F == 0 || D == 0)
	{
		return 0;
	}
	//clock = etu * F * etu_timer_fraction / D;
	clock = etu*F/D; 
	return clock;
}

void ETUTimer_Wait(uint32_t etu, uint8_t FiDi){
	ETUTimer_Delay(ETUTimer_ETU2Clock(etu, FiDi));
}


#if 0
static volatile uint32_t etu_timer_fraction = 8;
static volatile uint8_t etu_timeout_flag = 0;
static volatile uint8_t etu_alarm_flag = 0;

void timeout_action(void)
{
	etu_timeout_flag = 1;
}


void alarm_action(void)
{
	etu_alarm_flag = 1;
}

void ETUTimer_Init(uint32_t frequency)
{
	ClockCountor_Init(frequency);
	ClockAlarmer_Init(frequency);
}

uint32_t etu_to_clock(uint32_t etu, uint8_t FiDi)
{
	uint32_t F, D;
	uint32_t clock;
	
	F = convert_fi_code_to_value(FiDi >> 4);
	D = convert_di_code_to_value(FiDi & 0x0F);

	if( F == 0 || D == 0)
	{
		return 0;
	}
	//clock = etu * F * etu_timer_fraction / D;
	clock = etu*F/D; 
	return clock;
}

void ETUTimer_SetFrequency(uint32_t frequency)
{
	ClockCountor_SetCardClockFrequency(frequency);
	ClockAlarmer_SetCardClockFrequency(frequency);
	//etu_timer_fraction = ClockCountor_GetFrequency() / frequency;	
}

void ETUTimer_SetCountMultiple(uint32_t multiple)
{
	ClockCountor_SetCountMultiple(multiple);
}

void ETUTimer_Start(uint32_t etu, uint8_t FiDi)
{	
	uint32_t clock;

	clock = etu_to_clock(etu, FiDi);
	etu_timeout_flag = 0;
	ClockCountor_Start(clock, timeout_action);
}

void ETUTimer_Reset(void)
{
    etu_timeout_flag = 0;
    ClockCountor_Reset();
}

uint32_t ETUTimer_CheckTimeout(void)
{
	//return (etu_timeout_flag == 1) || (etu_alarm_flag == 1);
	return (etu_timeout_flag == 1); 
	//return 0;
}

void  ETUTimer_Stop(void)
{
    ClockCountor_Stop();
    etu_timeout_flag = 0;
}

void ETUTimer_Wait(uint32_t etu, uint8_t FiDi)
{
	ETUTimer_Start(etu, FiDi);
	while(etu_timeout_flag != 1);
	ETUTimer_Stop();
}

#endif 

#if 0
void ETUTimer_StartAlarmer(uint32_t etu, uint8_t FiDi)
{
	uint32_t clock;

	etu_alarm_flag = 0;	
	clock = etu_to_clock(etu, FiDi);	
	ClockAlarmer_Start(clock, alarm_action);
}

void ETUTimer_StopAlarmer(void)
{
	ClockAlarmer_Stop();
	etu_alarm_flag = 0;	
}
#endif 

#if 0

void test_ETUTimer(void)
{
	while(1)
	{
		//GPIO_SetBits(GPIOC, GPIO_Pin_1);
		GPIOC->BSRR = GPIO_Pin_1;
		ClockCountor_Wait(372 * 16);
		//GPIO_ResetBits(GPIOC, GPIO_Pin_1);
		GPIOC->BRR = GPIO_Pin_1;
		ClockCountor_Wait(372 * 16);
	}
}
#endif

